home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / general / raytrace / rayshade / graphtal.lzh / Graphtal.Amiga / Cone.C < prev    next >
C/C++ Source or Header  |  1992-11-19  |  5KB  |  230 lines

  1. /*
  2.  * Cone.C - methods for cone manipulations.
  3.  *
  4.  * Copyright (C) 1992, Christoph Streit (streit@iam.unibe.ch)
  5.  *                     University of Berne, Switzerland
  6.  * Copyright (C) 1989, 1991, Craig E. Kolb
  7.  * All rights reserved.
  8.  *
  9.  * This software may be freely copied, modified, and redistributed
  10.  * provided that this copyright notice is preserved on all copies.
  11.  *
  12.  * You may not distribute this software, in whole or in part, as part of
  13.  * any commercial product without the express consent of the authors.
  14.  *
  15.  * There is no warranty or other guarantee of fitness of this software
  16.  * for any purpose.  It is provided solely "as is".
  17.  *
  18.  */
  19.  
  20. #include "Cone.h"
  21. #include "Cylinder.h"
  22. #include "transform.h"
  23.  
  24. //___________________________________________________________ Cone
  25.  
  26. Cone::Cone(real r1, const Vector& bottom, 
  27.        real r2, const Vector& top)
  28. {
  29.   /*
  30.    * Find the axis and axis length.
  31.    */
  32.   Vector axis = top - bottom;
  33.   real len = axis.normalize();
  34.  
  35.   /*
  36.    * To render a cone, we transform the desired cone into
  37.    * a canonical, Z-axis aligned, unit length, unit radius
  38.    * at the apex cone.
  39.    */
  40.  
  41.   /*
  42.    * "tantheta" is the change in radius per unit length along
  43.    * the cone axis.
  44.    */
  45.   real tantheta = (r2-r1)/len;
  46.  
  47.   /*
  48.    * lprime defines the distance along the axis where the cone starts
  49.    */
  50.   real lprime = r1/tantheta;
  51.  
  52.   /*
  53.    * Find the true base (origin) of the cone.
  54.    */
  55.   Vector base = (-lprime)*axis + bottom;
  56.  
  57.   /*
  58.    * tlen is the total length of the cone.
  59.    */
  60.   real totalLengthOfCone = lprime+len;
  61.  
  62.   startDistance = lprime/totalLengthOfCone;
  63.  
  64.   trans = new TransMatrix(coordSystemTransform(base, axis, 
  65.                      r2, totalLengthOfCone));
  66.   itrans = new TransMatrix(*trans);
  67.   itrans->invert();
  68. }
  69.  
  70. GeoObject* Cone::create(real r1, const Vector& bottom, 
  71.             real r2, const Vector& top)
  72. {
  73.   /*
  74.    * Check the arguments.
  75.    */
  76.   if (equal(r1, r2))
  77.     return Cylinder::create(r1, bottom, top);
  78.       
  79.   if ((top-bottom).length() < EPSILON)
  80.     return NULL;
  81.  
  82.   if ((r1 < 0) || r2 < 0)
  83.     return NULL;
  84.  
  85.   /*
  86.    * The passed basepoint must be closer to the origin of the
  87.    * cone than the apex point, implying that the base radius
  88.    * must be smaller than the apex radius.  If the values passed
  89.    * reflect the opposite, we switch everything.
  90.    */
  91.   if (r2 < r1) 
  92.     return new Cone(r2, top, r1, bottom);
  93.   else
  94.     return new Cone(r1, bottom, r2, top);
  95. }
  96.  
  97. /*
  98.  * Ray cone intersection.
  99.  *
  100.  * The code is adapted from Craig Kolbs rayshade.
  101.  */
  102.  
  103. int Cone::intersect(const Ray& ray, real minDist, real& maxDist)
  104. {
  105.   real t1, t2, a, b, c, disc, zpos;
  106.  
  107.   intersectionTests++;
  108.  
  109.   a = ray.getDir()[0]*ray.getDir()[0] + ray.getDir()[1]*ray.getDir()[1] 
  110.     - ray.getDir()[2]*ray.getDir()[2];
  111.   b = ray.getDir()[0]*ray.getOrig()[0] + ray.getDir()[1]*ray.getOrig()[1] 
  112.     - ray.getDir()[2]*ray.getOrig()[2];
  113.   c = ray.getOrig()[0]*ray.getOrig()[0] + ray.getOrig()[1]*ray.getOrig()[1]
  114.     - ray.getOrig()[2]*ray.getOrig()[2];
  115.  
  116.   if (fabs(a) < EPSILON) {
  117.     /*
  118.      * Only one intersection point...
  119.      */
  120.     t1 = -0.5*c / b;
  121.     zpos = ray.getOrig()[2] + t1*ray.getDir()[2];
  122.     if (t1 < minDist || zpos < startDistance || zpos > 1.)
  123.       return FALSE;
  124.  
  125.     if (t1 < maxDist) {
  126.       maxDist = t1;
  127.       intersections++;
  128.       return TRUE;
  129.     }
  130.     return FALSE;
  131.   }
  132.   else {
  133.     disc = b*b - a*c;
  134.     if (disc < 0.)
  135.       return FALSE;        /* No possible intersection */
  136.  
  137.     disc = sqrt(disc);
  138.     t1 = (-b + disc) / a;
  139.     t2 = (-b - disc) / a;
  140.  
  141.     /*
  142.      * Clip intersection points.
  143.      */
  144.     zpos = ray.getOrig()[2] + t1*ray.getDir()[2];
  145.     if (t1 < minDist || zpos < startDistance || zpos > 1.) {
  146.       zpos = ray.getOrig()[2] + t2*ray.getDir()[2];
  147.       if (t2 < minDist || zpos < startDistance || zpos > 1.)
  148.     return FALSE;
  149.       else
  150.     t1 = t2;
  151.     } 
  152.     else {
  153.       zpos = ray.getOrig()[2] + t2*ray.getDir()[2];
  154.       if (t2 >= minDist && zpos >= startDistance && zpos <= 1. && t2 < t1)
  155.     t1 = t2;
  156.     }
  157.     if (t1 < maxDist) {
  158.       maxDist = t1;
  159.       intersections++;
  160.       return TRUE;
  161.     }
  162.     return FALSE;
  163.   }
  164. }
  165.  
  166. /*
  167.  * Compute cone normal at point p.
  168.  */
  169.  
  170. Vector Cone::normal(const Vector& p) const
  171. {
  172.   /*
  173.    * If p is on the z-axis, return the cone axis (0,0,1)
  174.    */
  175.   if (equal(p[0], 0) && equal(p[1], 0))
  176.     return Vector(0,0,1);
  177.  
  178.   /*
  179.    * The following is equal to (p*(0, 0, 1))*p
  180.    */
  181.   return Vector(p[0]*p[2], p[1]*p[2], -p[0]*p[0] - p[1]*p[1]);
  182. }
  183.  
  184.  
  185. /*
  186.  * Split the cone into polygon (rectangles)
  187.  */
  188.  
  189. PolygonList* Cone::tesselate(const BoundingBox&)
  190. {
  191.   const int resolution = 10;
  192.   real delta = 2*M_PI/(real)resolution;
  193.   real lastX = 1;
  194.   real lastY = 0;
  195.   real x, y;
  196.  
  197.   Polygon* p;
  198.   PolygonList* polys = new PolygonList(resolution);
  199.  
  200.   /* 
  201.    * Generate points on the edge of the disc.
  202.    */
  203.   for (real alpha=delta; alpha <= 2*M_PI; alpha += delta) {
  204.     x = cos(alpha); y = sin(alpha);
  205.     p = new Polygon(Vector(lastX*startDistance, 
  206.                lastY*startDistance, startDistance),
  207.             Vector(x*startDistance, y*startDistance, startDistance),
  208.             Vector(x, y, 1), Vector(lastX, lastY, 1));
  209.     p->transform(*trans);
  210.     polys->append(p);
  211.     lastX = x; lastY = y;
  212.   }
  213.  
  214.   return polys;
  215. }
  216.  
  217. /*
  218.  * If a transformation is given for the defined cone, postmultiply
  219.  * it to the already computed transformations.
  220.  */
  221.  
  222. int Cone::setTransform(TransMatrix* tmat)
  223. {
  224.   TransMatrix* matMul = new TransMatrix((*trans) * (*tmat));
  225.   delete itrans;
  226.   delete trans;
  227.  
  228.   return GeoObject::setTransform(matMul);
  229. }
  230.